#include "schedule.h"

static shedule_list ready_list, interrupt_list;
static pthread_mutex_t read_list_lk = PTHREAD_MUTEX_INITIALIZER;
static pthread_mutex_t irt_list_lk = PTHREAD_MUTEX_INITIALIZER;

void PostReadylist(TCB *p_tcb)
{
    pthread_mutex_lock(&read_list_lk);
    ready_list.list[ready_list.tail++] = p_tcb;
    pthread_mutex_unlock(&read_list_lk);
}

TCB *GetCurrentTcb()
{
    pthread_mutex_lock(&read_list_lk);
    if (ready_list.list[ready_list.head] == NULL)
    {
        printf("need insert first\n");
        pthread_mutex_unlock(&read_list_lk);
        return NULL;
    }
    TCB *CurrentTcb = ready_list.list[ready_list.head];
    pthread_mutex_unlock(&read_list_lk);
    return CurrentTcb;
}

thread_data * GetCurrentTaaskThread()
{
    TCB *CurrentTcb = GetCurrentTcb();

    if (CurrentTcb)
        return (thread_data *)(CurrentTcb->stackTop + 1);
    else
        return NULL;
}



void start_schedule()
{
    //get one to start first 
    thread_data * thread = NULL;
    thread = GetCurrentTaaskThread();
	if (NULL == thread)
	{
		printf("[%s] get start thread is NULL\n", __func__);
		return ;
	}

    pthread_mutex_lock(&thread->even->mutex);
    thread->even->event_triggered = true;
    pthread_cond_signal(&thread->even->cond);
    pthread_mutex_unlock(&thread->even->mutex);

	printf("[%s] get start thr ID: %x success\n", __func__, thread->pthread);

    return;
}

void switch_task_by_timeout()
{
    pthread_mutex_lock(&read_list_lk);
    if( (++ready_list.head) == ready_list.tail)
    {
        ready_list.head = 0; //loop
    }
    pthread_mutex_unlock(&read_list_lk);
}

void switch_task_by_chgSta(thread_data *run_thread)
{
    pthread_mutex_lock(&run_thread->even->mutex);
    if (run_thread->Stat == RUNNING)
        run_thread->Stat = WAITING;
    pthread_mutex_unlock(&run_thread->even->mutex);
}

void suspend_task(thread_data *thread)
{
    printf("%x suspend \n", thread->pthread);
    event *even = (thread->even);
    pthread_mutex_lock(&even->mutex);
    if(even->event_triggered == true && thread->Stat == WAITING)
    {
        //suspend it , pause here!!!
        even->event_triggered = false;
        //thread->Stat = WAITING;
        while (even->event_triggered == false)
        {
            printf("%x suspend waiting\n", thread->pthread);
            pthread_cond_wait(&even->cond, &even->mutex);
        }
        printf("%x suspend OK!!!!!\n", thread->pthread);
    }

    //trig it, go go go!!!
    thread->Stat = RUNNING;
    pthread_mutex_unlock(&even->mutex);
}

void resume_task(thread_data *thread)
{
    printf("%x resume \n", thread->pthread);
    pthread_mutex_lock(&thread->even->mutex);
    thread->even->event_triggered = true;
    pthread_cond_signal(&thread->even->cond);
    pthread_mutex_unlock(&thread->even->mutex);
}

void timer_schedule()
{
    //now only have timer slice cycle simple
    thread_data * thread = NULL;
    TCB * now_tcb = GetCurrentTcb();
    thread = GetCurrentTaaskThread();

    //need lock???
    if (thread->Stat != RUNNING)
        return;
    
    now_tcb->runtime_counter++;
    if(now_tcb->runtime_counter == now_tcb->assigned_time)
    {
		printf("thr:%s had run %d ticks,switch next\n", now_tcb->taskname,\
						now_tcb->runtime_counter);
        now_tcb->runtime_counter = 0;
        //timer slice used off
        //switch_task_by_timeout();
        //suspend_task(thread);
        //resume_task(GetCurrentTaaskThread());
        switch_task_by_chgSta(thread);
    }

    return;

}

void trap_stat_check()
{
    thread_data* curThr = NULL;
    if (curThr = GetCurrentTaaskThread())
    {   
        pthread_mutex_lock(&curThr->even->mutex);
        if (curThr->Stat == RUNNING)
        {
            //continue
            pthread_mutex_unlock(&curThr->even->mutex);
            return;
        }
        else if (curThr->Stat == WAITING)
        {
            pthread_mutex_unlock(&curThr->even->mutex);

            //switch
            switch_task_by_timeout();
            thread_data* next_thr = GetCurrentTaaskThread();
            resume_task(next_thr);

            //suspend current thr
            suspend_task(curThr);
        }
        
    }
}
